package com.myk.game.gobangchess.ai.symmetric;

import java.util.ArrayList;
import java.util.List;

/**
 * 该文件包含一个用于“对称棋”的局面类别打分函数。
 * 后续使用者可以通过调用 CategoryScorer.scoreByCategory(...) 来使用此功能。
 */
public class CategoryScorer {

    /**
     * 局面类别打分函数。
     * 该函数在某个玩家完成其回合后，从该玩家的视角对当前局面进行分类和打分。
     * 分数越高，代表局面越对该玩家有利。
     * 此函数为只读操作，不会修改传入的GameState对象。
     *
     * @param state       一个GameState对象，表示当前的完整游戏状态。
     *                    - 格式: GameState (定义于 GameState.java)
     *                    - 内容: 包含棋盘、所有棋块及其属性（对称性、大小等）。
     * @param playerColor 刚刚完成回合的玩家的颜色。
     *                    - 格式: int
     *                    - 内容: 1 代表黑棋, -1 代表白棋。
     * @return 返回一个整数分数，代表从 `playerColor` 视角下的局面评估。
     *         - -99999:  我方存在不对称棋块（必败局面）。
     *         - -10000: 双方均无不对称棋块。
     *         - 11000:   对方仅有一个大小小于5的不对称棋块。
     *         - 13000:   对方仅有一个大小大于等于5的不对称棋块。
     *         - 15000:   对方有多个不对称棋块，且大小均小于5。
     *         - 17000:   其他对我方有利的情况（例如，对方有多个不对称棋块，且至少一个大小大于等于5）。
     *         - 新增逻辑: 如果对方只有一个不对称棋块且大小<=10，并且能通过一次落子修复，则分数-1200。
     */
    public static int scoreByCategory(GameState state, int playerColor) {
        int myColor = playerColor;
        int opponentColor = -playerColor;

        // 规则 1: 检查我方是否存在不对称棋块。
        List<Boolean> mySymmetries = state.blockSymmetries.get(myColor);
        if (mySymmetries != null) {
            for (boolean isSymmetric : mySymmetries) {
                if (!isSymmetric) {
                    return -99999; // 我方存在不对称棋块，直接判负。
                }
            }
        }

        // 分析对方棋块。
        List<Boolean> opponentSymmetries = state.blockSymmetries.get(opponentColor);
        List<Integer> opponentSizes = state.blockSizes.get(opponentColor);
        List<List<int[]>> opponentSurroundingPoints = state.blockSurroundingPoints.get(opponentColor);

        List<Integer> opponentAsymmetricBlockIndices = new ArrayList<>();

        // 如果对方棋块列表存在，则找出所有不对称棋块的索引。
        if (opponentSymmetries != null) {
            for (int i = 0; i < opponentSymmetries.size(); i++) {
                if (!opponentSymmetries.get(i)) {
                    opponentAsymmetricBlockIndices.add(i);
                }
            }
        }

        // 规则 2: 如果对方没有不对称棋块（我方也没有，已在前面检查过）。
        if (opponentAsymmetricBlockIndices.isEmpty()) {
            return -10000;
        }

        // 规则 3: 对方存在不对称棋块。
        int asymmetricCount = opponentAsymmetricBlockIndices.size();
        int baseScore;

        if (asymmetricCount == 1) {
            int blockIndex = opponentAsymmetricBlockIndices.get(0);
            int blockSize = opponentSizes.get(blockIndex);
            if (blockSize < 5) {
                baseScore = 11000; // 规则 3.1
            } else {
                baseScore = 13000; // 规则 3.3
            }

            // --- 新增逻辑 ---
            // 如果对方只有一个不对称棋块，且大小小于等于10，检查是否能一步修复。
            if (blockSize <= 10) {
                List<int[]> surroundingPoints = opponentSurroundingPoints.get(blockIndex);
                if (canOpponentFixAsymmetry(state, opponentColor, surroundingPoints)) {
                    baseScore -= 1200; // 如果能修复，降低分数。
                }
            }
        } else { // asymmetricCount >= 2
            boolean allSmall = true;
            for (int index : opponentAsymmetricBlockIndices) {
                if (opponentSizes.get(index) >= 5) {
                    allSmall = false;
                    break;
                }
            }
            if (allSmall) {
                baseScore = 15000; // 规则 3.2
            } else {
                baseScore = 17000; // 规则 3.4
            }
        }

        return baseScore;
    }

    /**
     * 辅助函数：检查对方是否能通过一次落子修复其不对称性。
     *
     * @param originalState     当前的游戏状态。
     * @param opponentColor     对方玩家的颜色。
     * @param surroundingPoints 对方唯一不对称棋块的周围空位列表。
     * @return 如果存在一个落子位置可以使对方所有棋块都变为对称，则返回 true。
     */
    private static boolean canOpponentFixAsymmetry(GameState originalState, int opponentColor, List<int[]> surroundingPoints) {
        if (surroundingPoints == null || surroundingPoints.isEmpty()) {
            return false;
        }

        for (int[] point : surroundingPoints) {
            // 1. 创建一个临时的深拷贝状态用于模拟
            GameState tempState = originalState.deepCopy();

            // 2. 在模拟状态中添加对方棋子
            GameStateUpdater.addPiece(tempState, point[0], point[1], opponentColor);

            // 3. 检查模拟后对方是否还有不对称棋块
            List<Boolean> newSymmetries = tempState.blockSymmetries.get(opponentColor);
            boolean hasAsymmetry = false;
            if (newSymmetries != null) {
                for (boolean isSymmetric : newSymmetries) {
                    if (!isSymmetric) {
                        hasAsymmetry = true;
                        break;
                    }
                }
            }

            // 4. 如果模拟后没有不对称棋块了，说明可以修复
            if (!hasAsymmetry) {
                return true;
            }
        }

        // 遍历完所有可能的落子点都无法修复
        return false;
    }

    /**
     * 用于验证 scoreByCategory 函数的 main 方法。
     * 创建了多个棋盘场景，并打印出对应的分数。
     */
    public static void main(String[] args) {
        // 假设其他所需类 (BoardPrinter, GameStateGenerator, GameState, GameStateUpdater) 均已在项目中定义。

        // --- 原有测试用例 ---
        System.out.println("--- 测试用例 1: 我方(黑)存在不对称棋块 ---");
        int[][] board1 = new int[15][15];
        board1[5][5] = 1; board1[5][6] = 1; board1[5][7] = 1; board1[6][7] = 1;
        BoardPrinter.printBoardWithIndices(board1);
        GameState state1 = GameStateGenerator.getGameState(board1);
        int score1 = scoreByCategory(state1, 1);
        System.out.println("棋盘 1 分数 (黑方视角): " + score1);
        System.out.println();

        System.out.println("--- 测试用例 2: 双方均无不对称棋块 ---");
        int[][] board2 = new int[15][15];
        board2[5][5] = 1; board2[5][6] = 1; board2[5][7] = 1; board2[10][10] = -1;
        BoardPrinter.printBoardWithIndices(board2);
        GameState state2 = GameStateGenerator.getGameState(board2);
        int score2 = scoreByCategory(state2, 1);
        System.out.println("棋盘 2 分数 (黑方视角): " + score2);
        System.out.println();

        // --- 新增测试用例 ---

        System.out.println("--- 新增测试 1: 对方(白)有一个小不对称棋块(大小=2)，且无法一步修复 ---");
        int[][] boardNew1 = new int[15][15];
        boardNew1[7][7] = 1; // 我方对称
        boardNew1[2][2] = -1; // 对方不对称棋块
        boardNew1[2][3] = -1;
        BoardPrinter.printBoardWithIndices(boardNew1);
        GameState stateNew1 = GameStateGenerator.getGameState(boardNew1);
        int scoreNew1 = scoreByCategory(stateNew1, 1);
        System.out.println("新增棋盘 1 分数 (黑方视角): " + scoreNew1 + " (预期: 11000)");
        System.out.println();

        System.out.println("--- 新增测试 2: 对方(白)有一个小不对称棋块(大小=3)，且可以一步修复 ---");
        int[][] boardNew2 = new int[15][15];
        boardNew2[7][7] = 1; // 我方对称
        boardNew2[2][2] = -1; // 对方不对称棋块
        boardNew2[2][3] = -1;
        boardNew2[3][1] = -1;
        // 在 (3,3) 落子可形成2x2对称块
        BoardPrinter.printBoardWithIndices(boardNew2);
        GameState stateNew2 = GameStateGenerator.getGameState(boardNew2);
        int scoreNew2 = scoreByCategory(stateNew2, 1);
        System.out.println("新增棋盘 2 分数 (黑方视角): " + scoreNew2 + " (预期: 11000 - 1200 = 9800)");
        System.out.println();

        System.out.println("--- 新增测试 3: 对方(白)有一个大不对称棋块(大小=5)，且可以一步修复 ---");
        int[][] boardNew3 = new int[15][15];
        boardNew3[7][7] = 1; // 我方对称
        boardNew3[5][5] = -1; boardNew3[5][6] = -1; boardNew3[5][7] = -1;
        boardNew3[6][5] = -1; boardNew3[6][6] = -1;
        // 在 (6,6) 落子可形成3x3对称块
        BoardPrinter.printBoardWithIndices(boardNew3);
        GameState stateNew3 = GameStateGenerator.getGameState(boardNew3);
        int scoreNew3 = scoreByCategory(stateNew3, 1);
        System.out.println("新增棋盘 3 分数 (黑方视角): " + scoreNew3 + " (预期: 13000 - 1200 = 11800)");
        System.out.println();

        System.out.println("--- 新增测试 4: 对方(白)有一个大不对称棋块(大小=11)，超过大小10的限制，不可修复 ---");
        int[][] boardNew4 = new int[15][15];
        boardNew4[7][7] = 1; // 我方对称
        // 一个大小为11的不对称棋块
        boardNew4[5][5] = -1; boardNew4[5][6] = -1; boardNew4[5][7] = -1; boardNew4[5][8] = -1;
        boardNew4[6][5] = -1; boardNew4[6][6] = -1; boardNew4[6][7] = -1;
        boardNew4[7][5] = -1; boardNew4[7][6] = -1;
        boardNew4[8][5] = -1; boardNew4[8][6] = -1;
        BoardPrinter.printBoardWithIndices(boardNew4);
        GameState stateNew4 = GameStateGenerator.getGameState(boardNew4);
        int scoreNew4 = scoreByCategory(stateNew4, 1);
        System.out.println("新增棋盘 4 分数 (黑方视角): " + scoreNew4 + " (预期: 13000)");
        System.out.println();
    }
}